package fun.easycode.jointblock.util;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import fun.easycode.jointblock.core.Alias;
import fun.easycode.jointblock.core.DynamicOperate;
import fun.easycode.jointblock.exception.CheckException;

import java.lang.reflect.Field;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * entity update log 工具类
 *  用来获取实体的修改日志，哪些字段变更了
 * @author xuzhen97
 */

public class LogUtil {

    private static final ThreadLocal<Map<String, String>> OLD_ENTITY_JSON = ThreadLocal.withInitial(HashMap::new);
    private static final ThreadLocal<Map<String, String>> NEW_ENTITY_JSON = ThreadLocal.withInitial(HashMap::new);
    private static final ThreadLocal<Map<String, Queue<Object>>> UPDATE_FIELD_QUEUE = ThreadLocal.withInitial(HashMap::new);

    /**
     * 设置原先的实体
     * @param key String 唯一id, 实体id
     * @param oldEntity 实体
     */
    public static void setOldEntity(String key, Object oldEntity){
        OLD_ENTITY_JSON.get().put(key, JacksonUtil.toJson(oldEntity));
    }

    /**
     * 设置修改后的实体
     * @param key String 唯一id, 实体id
     * @param oldEntity Object
     */
    public static void setNewEntity(String key, Object oldEntity){
        NEW_ENTITY_JSON.get().put(key, JacksonUtil.toJson(oldEntity));
    }

    public static void setUpdateField(String key, String fieldName, Object fieldValue){
        Queue<Object> queue = UPDATE_FIELD_QUEUE.get().computeIfAbsent(key, k-> new LinkedList<>());
        queue.offer(fieldName);
        queue.offer(fieldValue);
    }

    /**
     * 获取update log 先调用
     * setOldEntity
     * setNewEntity
     *  获取后数据会被清除，自行保存字符串
     * @param key String
     * @return String
     */
    public static String getUpdateLog(String key){

        String oldJson = OLD_ENTITY_JSON.get().get(key);
        String newJson = NEW_ENTITY_JSON.get().get(key);

        OLD_ENTITY_JSON.get().remove(key);
        NEW_ENTITY_JSON.get().remove(key);

        return JacksonUtil.diff(oldJson, newJson);
    }

    /**
     * 获取数据修改日志
     * @param key
     * @return
     */
    public static <T> String getFieldUpdateLog(String key, T entity){
        Queue<Object> queue = UPDATE_FIELD_QUEUE.get().get(key);

        Map<String, Field> entityFieldMap = ReflectUtil
                .getFieldMap(entity.getClass()).entrySet().stream().map(entry->{
                    // 将field map key转换成小写_ 的形式，如果Alias有值就取
                    // 这里其实就是为了转换成数据库filed的形式，为了和mybatis对起来
                    String mapKey;
                    if(AnnotationUtil.hasAnnotation(entry.getValue(), Alias.class)) {
                        Alias alias = entry.getValue().getAnnotation(Alias.class);
                        mapKey = alias.value();
                    }else{
                        mapKey = DynamicOperate.camel2under(entry.getKey());
                    }

                    return new AbstractMap.SimpleEntry<>(mapKey, entry.getValue());
                })
                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

        StringBuilder updateLogBuilder = new StringBuilder();

        while (!queue.isEmpty()){

            String updateFieldName = (String) queue.remove();
            Object updateFieldValue = queue.remove();

            Field entityField = entityFieldMap.get(updateFieldName);

            if(entityField == null){
                throw new CheckException("数据库实体字段不存在！");
            }

            Object entityFieldValue =  ReflectUtil.getFieldValue(entity, entityField);
            // 只有值真正改变的才会打印日志
            if(ObjectUtil.notEqual(updateFieldValue, entityFieldValue)) {
                updateLogBuilder.append("[key=").append(updateFieldName).append(",oldValue=")
                        .append(entityFieldValue).append(",newValue=").append(updateFieldValue).append("];");
            }
        }
        UPDATE_FIELD_QUEUE.get().remove(key);

        return updateLogBuilder.toString();
    }

}
